<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="author" content="GoJun" />
	
	
	
	<title>通俗易懂了解 Android 设计模式 - 观察者模式 ｜ GoJun</title>
	
    
    
    <meta name="description" content="介绍 设计模式有三大类分别是创建型模式、结构型模式和行为型模式， 而观察者模式是属于行为型模式中的一种。 观察者模式又称为 “发布/订阅模式”，是一个使用频率非常高的模式之一，主要的作用是解耦，将被观察者和观" />
    

    
    
    <meta name="keywords" content="Hugo, theme, zozo" />
    

	
    
    <link rel="shortcut icon" href="https://gojun.me/images/favicon.ico" />

    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.mecss/normalize.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/zozo.css" />
	<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/highlight.css" />

    
    
</head>

<body>
    <div class="main animate__animated animate__fadeInDown">
        <div class="nav_container animated fadeInDown">
    <div class="site_nav" id="site_nav">
        <ul>
            
            <li>
                <a href="/">Home</a>
            </li>
            
            <li>
                <a href="/posts/">Archive</a>
            </li>
            
            <li>
                <a href="/tags/">Tags</a>
            </li>
            
            <li>
                <a href="/projects/">Projects</a>
            </li>
            
        </ul>
    </div>
    <div class="menu_icon">
        <a id="menu_icon"><i class="ri-menu-line"></i></a>
    </div>
</div>
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <h1>
                <a href="https://gojun.me">
                    <span>GoJun</span>
                </a>
            </h1>
        </div>
        <div class="description">
            <p class="sub_title">为向往生活努力奋斗！</p>
            <div class="my_socials">
                
                
                <a href="https://github.com/freelander" title="github" target="_blank"><i class="ri-github-fill"></i></a>
                
                
                <a href="https://gojun.me/index.xml" type="application/rss+xml" title="rss" target="_blank"><i
                        class="ri-rss-fill"></i></a>
            </div>
        </div>
    </div>
</div>
        <div class="content">
            <div class="post_page">
                <div class="post animate__animated animate__fadeInDown">
                    <div class="post_title post_detail_title">
                        <h2><a href='/posts/android-observer-mode/'>通俗易懂了解 Android 设计模式 - 观察者模式</a></h2>
                        <span class="date">2021.08.07</span>
                    </div>
                    <div class="post_content markdown"><h3 id="介绍">介绍</h3>
<p>设计模式有三大类分别是创建型模式、结构型模式和行为型模式， 而观察者模式是属于行为型模式中的一种。
观察者模式又称为 “发布/订阅模式”，是一个使用频率非常高的模式之一，主要的作用是解耦，将被观察者和观察者解耦，使得它们之间减少依赖，甚至没有任何依赖。</p>
<h3 id="定义">定义</h3>
<p>定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。</p>
<h3 id="使用场景">使用场景</h3>
<ul>
<li>关联行为场景，需要注意的是，关联行为是可拆分的，而不是 “组合” 关系；</li>
<li>事件多级触发场景；</li>
<li>跨系统的消息交换场景，如消息队列，事件总线的处理机制。</li>
</ul>
<h3 id="uml-类图">UML 类图</h3>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2021/08/android-observer-mode-02.png">
<img src="/images/2021/08/android-observer-mode-02.png" alt="img"  />
</a>
</div>

</p>
<h4 id="角色解释">角色解释：</h4>
<ul>
<li>Subject（抽象被观察者）：所有对观察者对象的引用都保存在一个集合中，每个主体可以有任意数量的观察者，提供了添加和删除观察者对象的方法。</li>
<li>ConcreteSubject（具体被观察者）：将相关状态存储在特定的 Observer Object 中，当特定 Subject 的内部状态发生变化时通知所有注册的观察者。</li>
<li>Observer（抽象观察者）：为所有特定的观察者定义一个接口，以便在收到主题通知时进行自我更新。</li>
<li>ConcrereObserver（具体观察者）：实现由抽象观察者定义的更新接口，当主题发生变化时更新自身状态。</li>
</ul>
<h3 id="举个例子">举个例子</h3>
<p>从工作事例中挑选一个场景来简单理解下观察者模式，比如公司通知员工进行打疫苗事项。</p>
<h4 id="观察者">观察者</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Description: 员工是观察者
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Worker</span> <span class="kd">implements</span> <span class="n">Observer</span> <span class="o">{</span>

    <span class="kd">public</span> <span class="n">String</span> <span class="n">name</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">Worker</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">update</span><span class="o">(</span><span class="n">Observable</span> <span class="n">o</span><span class="o">,</span> <span class="n">Object</span> <span class="n">arg</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">name</span> <span class="o">+</span> <span class="s">&#34;, &#34;</span> <span class="o">+</span> <span class="n">arg</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="s">&#34;员工：&#34;</span> <span class="o">+</span> <span class="n">name</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>

</code></pre></div><h4 id="被观察者">被观察者</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Description: 公司作为被观察者
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Company</span> <span class="kd">extends</span> <span class="n">Observable</span> <span class="o">{</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">postNoticeMsg</span><span class="o">(</span><span class="n">String</span> <span class="n">msg</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// 标识状态或者内容发生改变
</span><span class="c1"></span>        <span class="n">setChanged</span><span class="o">();</span>
        <span class="c1">// 通知所有员工
</span><span class="c1"></span>        <span class="n">notifyObservers</span><span class="o">(</span><span class="n">msg</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h3 id="测试代码">测试代码</h3>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Description:测试
</span><span class="cm"> */</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ObserverDemo</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// 被观察的角色-公司
</span><span class="c1"></span>        <span class="n">Company</span> <span class="n">company</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Company</span><span class="o">();</span>

        <span class="c1">// 观察者-员工
</span><span class="c1"></span>        <span class="n">Worker</span> <span class="n">worker</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Worker</span><span class="o">(</span><span class="s">&#34;小二&#34;</span><span class="o">);</span>
        <span class="n">Worker</span> <span class="n">worker1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Worker</span><span class="o">(</span><span class="s">&#34;小三&#34;</span><span class="o">);</span>
        <span class="n">Worker</span> <span class="n">worker2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Worker</span><span class="o">(</span><span class="s">&#34;小四&#34;</span><span class="o">);</span>
        <span class="n">Worker</span> <span class="n">worker3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Worker</span><span class="o">(</span><span class="s">&#34;小五&#34;</span><span class="o">);</span>
        <span class="n">Worker</span> <span class="n">worker4</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Worker</span><span class="o">(</span><span class="s">&#34;小六&#34;</span><span class="o">);</span>

        <span class="c1">// 把员工添加到公司中
</span><span class="c1"></span>        <span class="n">company</span><span class="o">.</span><span class="na">addObserver</span><span class="o">(</span><span class="n">worker</span><span class="o">);</span>
        <span class="n">company</span><span class="o">.</span><span class="na">addObserver</span><span class="o">(</span><span class="n">worker1</span><span class="o">);</span>
        <span class="n">company</span><span class="o">.</span><span class="na">addObserver</span><span class="o">(</span><span class="n">worker2</span><span class="o">);</span>
        <span class="n">company</span><span class="o">.</span><span class="na">addObserver</span><span class="o">(</span><span class="n">worker3</span><span class="o">);</span>
        <span class="n">company</span><span class="o">.</span><span class="na">addObserver</span><span class="o">(</span><span class="n">worker4</span><span class="o">);</span>

        <span class="c1">// 发布信息
</span><span class="c1"></span>        <span class="n">company</span><span class="o">.</span><span class="na">postNoticeMsg</span><span class="o">(</span><span class="s">&#34;明天公司安排你打疫苗&#34;</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h4 id="结果">结果</h4>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2021/08/android-observer-mode-01.png">
<img src="/images/2021/08/android-observer-mode-01.png" alt="img"  />
</a>
</div>

</p>
<p>从结果来看，所有被注册到公司的员工，公司只要发送通知，底下所有员工都能收到消息，这就是观察者模式的一对多依赖关系，它们之间没有任何耦合。</p>
<h3 id="总结">总结</h3>
<p>从上面例子带大家简单了解下观察者模式，Observer 和 Observable 均是 Java JDK 中的内置类型，可见观察者模式是非常重要的。</p>
<p>其实观察模式在 Android 里被广泛应用，简单列举下应用的地方：</p>
<ul>
<li>BroadcastReceiver 作为 Android 的四大组件之一，实际上也是一个典型的观察者模式；</li>
<li>Android 官方架构组件 LiveData；</li>
<li>ListView 和 RecyclerView 列表控件中的 notifyDataSetChanged 方法；</li>
<li>还有一些著名的第三方库 如 RxJava、RxAndroid、EventBus 等等。</li>
</ul>
<p>因此大家有必要了解学习观察者模式，下面再简单总结下观察者模式的优缺点：</p>
<h4 id="优点">优点</h4>
<ul>
<li>观察者和被观察者是分开的，它们之间是抽象的耦合而不是具体，因此它们各自更改不会影响到对方；</li>
<li>易于扩展，提升系统灵活性。</li>
</ul>
<h4 id="缺点">缺点</h4>
<ul>
<li>在使用观察者模式时，需要考虑开发和运行效率问题，程序中包括一个被观察者、多个观察者、开发和调试等内容会比较复杂，而且在 Java 中消息的通知默认是顺序执行的，
一个观察者卡顿，会影响到整体的执行效率，在这种情况下，一般考虑采用异步的方式；</li>
<li>滥用会造成冗余的数据通知。</li>
</ul>
<h3 id="参考链接">参考链接</h3>
<ul>
<li><a href="https://programmer.help/blogs/android-design-patterns-observer-patterns.html">Android Design Patterns - Observer Patterns</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/143479553">Android 设计模式学习（二）观察者模式应用实例</a></li>
</ul>
</div>
                    <div class="post_footer">
                        
                        <div class="meta">
                            <div class="info">
                                <span class="field tags">
                                    <i class="ri-stack-line"></i>
                                    
                                    <a href="https://gojun.me/tags/android/">Android</a>
                                    
                                    <a href="https://gojun.me/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">设计模式</a>
                                    
                                </span>
                            </div>
                        </div>
                        
                    </div>
                </div>
                
                
                <div class="doc_comments"></div>
                
            </div>
        </div>
    </div>
    <a id="back_to_top" href="#" class="back_to_top"><i class="ri-arrow-up-s-line"></i></a>
    <footer class="footer">
    <div class="footer_slogan">
        <span></span>
    </div>
</footer>
    <script src="https://gojun.me/js/jquery-3.5.1.min.js"></script>
<link href="https://gojun.me/css/fancybox.min.css" rel="stylesheet">
<script src="https://gojun.me/js/fancybox.min.js"></script>
<script src="https://gojun.me/js/zozo.js"></script>


<script type="text/javascript" async
    src="https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        MathJax.Hub.Config({
            tex2jax: {
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                displayMath: [['$$', '$$'], ['\[\[', '\]\]']],
                processEscapes: true,
                processEnvironments: true,
                skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
                TeX: {
                    equationNumbers: { autoNumber: "AMS" },
                    extensions: ["AMSmath.js", "AMSsymbols.js"]
                }
            }
        });

        MathJax.Hub.Queue(function () {
            
            
            
            var all = MathJax.Hub.getAllJax(), i;
            for (i = 0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

<style>
    code.has-jax {
        font: inherit;
        font-size: 100%;
        background: inherit;
        border: inherit;
        color: #515151;
    }
</style>



<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-142037913-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>

</body>

</html>